package com.dhcc.bpm.common.redisMessage;

import com.dhcc.bpm.common.utils.IpAddressUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RedisLock {

    private static final Logger log = LoggerFactory.getLogger(RedisMessageSender.class);

    private RedisService redisService;

    /**
     * Lock key path.
     */
    private String lockKey;

    /**
     * 锁超时时间，防止线程在入锁以后，无限的执行等待
     */
    private Long expireSecond = 30L;

    /**
     * 锁等待时间，防止线程饥饿
     */
    private volatile boolean locked = false;

    /**
     * Detailed constructor with default acquire timeout 10000 msecs and lock expiration of 60000 msecs.
     *
     * @param lockKey lock key (ex. account:1, ...)
     */
    public RedisLock(RedisService redisService, String lockKey) {
        this.redisService = redisService;
        this.lockKey = lockKey + "_lock";
    }

    /**
     * Detailed constructor.
     */
    public RedisLock(RedisService redisService, String lockKey, Long expireSecond) {
        this(redisService, lockKey);
        this.expireSecond = expireSecond;
    }

    /**
     * @return lock key
     */
    public String getLockKey() {
        return lockKey;
    }


    /**
     * 获得 lock.
     * 实现思路: 主要是使用了redis 的setnx命令,缓存了锁.
     * reids缓存的key是锁的key,所有的共享, value是锁的到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间)
     * 执行过程:
     * 1.通过setnx尝试设置某个key的值,成功(当前没有这个锁)则返回,成功获得锁
     * 2.锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值
     *
     * @return true if lock is acquired, false acquire timeouted
     */
    public synchronized boolean lock() {

        log.info("获取当前进程的ip为：{}", IpAddressUtil.getIpAddress());
        if (redisService.setNx(lockKey, IpAddressUtil.getIpAddress(), expireSecond)) {
            // lock acquired
            locked = true;
            log.info("ip为{}获取锁成功", IpAddressUtil.getIpAddress());
            return true;
        }
        return false;
    }


    /**
     * Acqurired lock release.
     */
    public synchronized void unlock() {
        if (locked) {
            redisService.remove(lockKey);
            locked = false;
            log.info("ip为{}解锁成功", IpAddressUtil.getIpAddress());
        }
    }

}
